export default class Matrix3 {
    private _data: number[] = new Array(9);
    constructor(values?: number[]) {
        if (!values) {
            this._data = Matrix3.Identity._data;
            return;
        }
        if (values.length !== 9) {
            throw new Error('Matrix3 must consists of 9 values (3 * 3)');
        }
        this._data = values;
    }
    static get Identity() {
        return new Matrix3([
            1, 0, 0,
            0, 1, 0,
            0, 0, 1
        ]);
    }
    static translation(dx: number, dy: number) {
        return new Matrix3([
            1, 0, 0,
            0, 1, 0,
            dx, dy, 1,
        ]);
    }
    static rotation(rad) {
        const cos = Math.cos(rad);
        const sin = Math.sin(rad);
        return new Matrix3([
            cos, -sin, 0,
            sin, cos, 0,
            0, 0, 1,
        ]);
    }
    static scaling(sx, sy) {
        return new Matrix3([
            sx, 0, 0,
            0, sy, 0,
            0, 0, 1,
        ]);
    }
    get(row: number, col: number): number {
        row = Math.floor(row);
        col = Math.floor(col);
        if (row > 2) throw new Error('Row index in matrix3 is in range [0,2]');
        if (col > 2) throw new Error('Col index in matrix3 is in range [0,2]');
        return this._data[row * 3 + col];
    }
    mul(other: Matrix3): Matrix3 {
        const a00 = this._data[0 * 3 + 0];
        const a01 = this._data[0 * 3 + 1];
        const a02 = this._data[0 * 3 + 2];
        const a10 = this._data[1 * 3 + 0];
        const a11 = this._data[1 * 3 + 1];
        const a12 = this._data[1 * 3 + 2];
        const a20 = this._data[2 * 3 + 0];
        const a21 = this._data[2 * 3 + 1];
        const a22 = this._data[2 * 3 + 2];
        const b00 = other._data[0 * 3 + 0];
        const b01 = other._data[0 * 3 + 1];
        const b02 = other._data[0 * 3 + 2];
        const b10 = other._data[1 * 3 + 0];
        const b11 = other._data[1 * 3 + 1];
        const b12 = other._data[1 * 3 + 2];
        const b20 = other._data[2 * 3 + 0];
        const b21 = other._data[2 * 3 + 1];
        const b22 = other._data[2 * 3 + 2];
        return new Matrix3([
            b00 * a00 + b01 * a10 + b02 * a20,
            b00 * a01 + b01 * a11 + b02 * a21,
            b00 * a02 + b01 * a12 + b02 * a22,

            b10 * a00 + b11 * a10 + b12 * a20,
            b10 * a01 + b11 * a11 + b12 * a21,
            b10 * a02 + b11 * a12 + b12 * a22,

            b20 * a00 + b21 * a10 + b22 * a20,
            b20 * a01 + b21 * a11 + b22 * a21,
            b20 * a02 + b21 * a12 + b22 * a22,
        ]);
    }
    translate(dx, dy) {
        return this.mul(Matrix3.translation(dx, dy));
    }
    rotate(rad) {
        return this.mul(Matrix3.rotation(rad));
    }
    scale(sx, sy) {
        return this.mul(Matrix3.scaling(sx, sy));
    }
}
